# -*- coding: utf-8 -*-
import ui_udpchatroom,tcpserver,tcpclient,privatechat,weather
import socket,sys,re,os
from enum import Enum
from PyQt5.QtGui import QFont
from PyQt5.QtCore import QDataStream,QByteArray,QIODevice,QProcess,QDateTime,Qt,QTextCodec
from PyQt5.QtWidgets import QWidget,QApplication,QMessageBox,QTableWidgetItem,QAbstractItemView,QFontDialog,QInputDialog,QColorDialog,QFileDialog
from PyQt5.QtNetwork import QUdpSocket,QHostAddress,QHostInfo


class MessageType(Enum):
    Message = 0
    NewParticipant = 1
    ParticipantLeft = 2
    FileName = 3
    Refuse = 4

class UdpChatRoom(ui_udpchatroom.Ui_Form,QWidget):

    def __init__(self):
        super(UdpChatRoom,self).__init__()
        self.ui = ui_udpchatroom.Ui_Form()
        self.ui.setupUi(self)

        self.udpSocket = QUdpSocket()
        self.server = tcpserver.TcpServer()


        self.port = 45454
        self.fileName = ""
        self.server.sendFileName.connect(self.getFileName)
        self.udpSocket.bind(self.port,QUdpSocket.ShareAddress|QUdpSocket.ReuseAddressHint)
        self.udpSocket.readyRead.connect(self.processPendingDatagrams)  # 接收消息
        self.sendMessage(MessageType.NewParticipant)#广播登录信息

        #按钮槽函数
        self.ui.sendButton.clicked.connect(self.sendBtn_clicked)
        self.ui.quitButton.clicked.connect(self.quitBtn_clicked)
        self.ui.fontButton.clicked.connect(self.setFontBtn_clicked)
        self.ui.colorButton.clicked.connect(self.setColorBtn_clicked)
        self.ui.sendFileBtn.clicked.connect(self.sendFileBtn_clicked)
        self.ui.weatherButton.clicked.connect(self.weatherBtn_clicked)
        self.ui.catchpicBtn.clicked.connect(self.catchpicBtn_clicked)

        self.ui.tableWidget.cellDoubleClicked.connect(self.private_chat)

        #self.ui.messageEdit.currentCharFormatChanged(QTextCharFormat).connect()

    #udp广播登录信息
    def sendMessage(self,msgType,serverAddress=""):

        messageWrite = QByteArray() #定义一个写的缓冲区

        out = QDataStream(messageWrite,QIODevice.WriteOnly)

        address = self.getIp()#获得本机IP
        localHostName = QHostInfo.localHostName()

        out.writeInt32(msgType.value)
        out.writeQString(self.getUserName())
        out.writeQString(localHostName)

        if msgType == MessageType.Message :
            sendText = self.ui.messageEdit.toPlainText()  # 获得输入框的消息
            if sendText == "" :
                QMessageBox.warning(self,"警告","发送内容不能为空",QMessageBox.Ok)
                return
            out.writeQString(address)
            out.writeQString(self.getMessage())

            self.ui.messageBrowser.verticalScrollBar().setValue\
                (self.ui.messageBrowser.verticalScrollBar().maximum())


        if msgType == MessageType.NewParticipant:#如果是新用户上线，输出IP地址
            out.writeQString(address)

        if msgType == MessageType.ParticipantLeft:
            pass

        if msgType == MessageType.FileName:
            row = self.ui.tableWidget.currentRow()
            clientAddress = self.ui.tableWidget.item(row,2).text()
            out.writeQString(address)
            out.writeQString(clientAddress)
            out.writeQString(self.fileName)

        if msgType == MessageType.Refuse:
            out.writeQString(serverAddress)

        self.udpSocket.writeDatagram(messageWrite,QHostAddress.Broadcast,self.port)#广播
    #接收UDP广播发送的数据
    def processPendingDatagrams(self):

        while self.udpSocket.hasPendingDatagrams() :


            messageRead = QByteArray() #定义一个读的缓冲区
            messageRead.resize(self.udpSocket.pendingDatagramSize())
            messageBuf,ipAddress,port =self.udpSocket.readDatagram(messageRead.size())

            #将messageBuf 转换成QByteArray格式
            messageRead = QByteArray(messageBuf)

            inStream = QDataStream(messageRead,QIODevice.ReadOnly)
            msgType=inStream.readInt32()

            messageTime = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss")

            if msgType == 0:

                userName = inStream.readQString()
                localHostName=inStream.readQString()
                ipAddress = inStream.readQString()
                messageInfo = inStream.readQString()

                self.ui.messageBrowser.setTextColor(Qt.blue)
                self.ui.messageBrowser.setCurrentFont(QFont("Times New Roman",12))
                self.ui.messageBrowser.append("["+userName+"]"+messageTime)
                self.ui.messageBrowser.append(messageInfo)


            if msgType == 1:

                userName = inStream.readQString()
                localHostName = inStream.readQString()
                ipAddress = inStream.readQString()

                self.newParticipant(userName,localHostName,ipAddress)

            if msgType == 2:
                userName = inStream.readQString()
                localHostName = inStream.readQString()
                self.participantLeft(userName,localHostName,messageTime)

            if msgType == 3:
                userName = inStream.readQString()
                localHostName = inStream.readQString()
                ipAddress = inStream.readQString()
                clientAddress = inStream.readQString()
                fileName = inStream.readQString()
                self.hasPendingFile(userName,ipAddress,clientAddress,fileName)

            if msgType == 4:
                userName = inStream.readQString()
                localHostName = inStream.readQString()
                serverAddress = inStream.readQString()
                ipAddress = self.getIp()
                if ipAddress == serverAddress :
                    self.server.refused()

    # 新用户处理
    def newParticipant(self,userName,localHostName,ipAddress):
        userList = self.ui.tableWidget.findItems(localHostName,Qt.MatchExactly)
        if not len(userList):
            user = QTableWidgetItem(userName)
            host = QTableWidgetItem(localHostName)
            ip = QTableWidgetItem(ipAddress)

            self.ui.tableWidget.insertRow(0)
            self.ui.tableWidget.setItem(0,0,user)
            self.ui.tableWidget.setItem(0,1,host)
            self.ui.tableWidget.setItem(0,2,ip)
            self.ui.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)

            self.ui.messageBrowser.setTextColor(Qt.gray)
            self.ui.messageBrowser.setCurrentFont(QFont("Roman times",10))
            self.ui.messageBrowser.append(("{}在线！").format(userName))
            self.ui.userNumLabel.setText(("在线人数：{:.0f}").format(self.ui.tableWidget.rowCount()))

            self.sendMessage(MessageType.NewParticipant)

    #　用户离开处理
    def participantLeft(self,userName,localHostName,messageTime):
        #rowNum = self.ui.tableWidget.findItems(localHostName, Qt.MatchExactly)

        rowList = self.ui.tableWidget.findItems(localHostName,Qt.MatchExactly)

        rowNum = self.ui.tableWidget.row(rowList[0])

        self.ui.tableWidget.removeRow(rowNum)
        self.ui.messageBrowser.setTextColor(Qt.gray)
        self.ui.messageBrowser.setCurrentFont(QFont("Roman times",10))
        self.ui.messageBrowser.append(("{}于{}离开！").format(userName,messageTime))
        self.ui.userNumLabel.setText(("在线人数：{:.0f}").format(self.ui.tableWidget.rowCount()))

    #私聊函数
    def private_chat(self):
        ipaddress = self.ui.tableWidget.selectedItems()
        itemRow = ipaddress[0].row()

        ip = self.ui.tableWidget.item(itemRow,2).text()
        username = self.ui.tableWidget.item(itemRow,0).text()
        targetInfo = username+";"+ip

        if not len(ip):
            QMessageBox.warning(self,"警告","未检测到对方IP",QMessageBox.Ok)
            return
        self.p_chat = privatechat.PrivateChat()
        self.p_chat.sendData(targetInfo)
        self.p_chat.setObjectName(ip)
        self.p_chat.setAttribute(Qt.WA_DeleteOnClose)
        self.p_chat.show()
    #获取输入的聊天信息
    def getMessage(self):
        msg = self.ui.messageEdit.toHtml()

        self.ui.messageEdit.clear()
        self.ui.messageEdit.setFocus()

        return msg

    #发送消息
    def sendBtn_clicked(self):
        self.sendMessage(MessageType.Message)

    #获取要发送的文件名
    def getFileName(self,name):
        self.fileName = name
        self.sendMessage(MessageType.FileName)

    #发送文件按钮
    def sendFileBtn_clicked(self):
        if not len(self.ui.tableWidget.selectedItems()):
            QMessageBox.warning(self,"选择用户","请先从用户列表选择要传送的用户！",QMessageBox.Ok)
            return

        self.server.show()
        self.server.initServer()

    # 当前窗口截图截图
    def catchpicBtn_clicked(self):
        screen = QApplication.primaryScreen()
        winid = self.winId()
        pix = screen.grabWindow(int(winid))

        filename, flag = QInputDialog.getText(self, "设置截图文件名", "请输入文件名")
        currentPath = os.path.abspath('.')
        root = currentPath + "/catchImg/"
        if not os.path.exists(root):
            os.mkdir(root)
        path = root + filename + ".jpg"
        pix.save(path)

    # 天气信息按钮
    def weatherBtn_clicked(self):
        self.weather = weather.Weather()
        self.weather.show()

    #是否接收文件
    def hasPendingFile(self,userName,serverAddress,clientAddress,fileName):
        ipAddress = self.getIp()
        if ipAddress == clientAddress :
            btn = QMessageBox.information(self,"接收文件","来自{}({})的文件：{},"
                    "是否接收？".format(userName,serverAddress
                                   ,fileName),QMessageBox.Yes,QMessageBox.No)
            if btn == QMessageBox.Yes :
                nameTuple = QFileDialog.getSaveFileName(self,"保存文件",fileName)
                name =str(nameTuple)
                if len(name) :
                    nameList = name.split(',')
                    thefilename = nameList[0].strip("('")
                    self.client = tcpclient.TcpClient()
                    self.client.setFileName(thefilename)
                    self.client.setHostAddress(QHostAddress(serverAddress))
                    self.client.show()
            else:
                self.sendMessage(MessageType.Refuse,serverAddress)

    #设置颜色
    def setColorBtn_clicked(self):
        color = QColorDialog.getColor()
        if color.isValid():
            self.ui.messageEdit.setTextColor(color)

    #设置字体
    def setFontBtn_clicked(self):
        font, ok = QFontDialog.getFont()
        if ok:
            self.ui.messageEdit.setCurrentFont(font)

    def currentFormatChanged(self,textFormat):
        pass

    #获取ip
    def getIp(self):
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.connect(('8.8.8.8', 80))
            ip = s.getsockname()[0]
        finally:
            pass

        return ip
    """# 本地IP
    def getLocalIP(self):
        ipList = []
        nd = psutil.net_if_addrs()
        for i, j in nd.items():
            for item in j:
                if item[0] == 2 and not item[1] == '127.0.0.1':
                    ipList.append((i, item[1]))
        return ipList[0][1]"""

    # 获取用户名
    def getUserName(self):
        envVabList = ["USERNAME.*","USER.*" , "USERDOMAIN.*", "HOSTNAME.*", "DOMAINNAME.*"]

        envrmList = QProcess.systemEnvironment()

        for envStr in envVabList:
            for envrmStr in envrmList:
                reRtn=re.search(envStr,envrmStr)
                if reRtn is None:
                    continue
                else:
                    break
            if reRtn:
                usrReRtn=reRtn.group()

                listIndex = envrmList.index(usrReRtn)

                if listIndex != 1:
                    stringList = envrmList[listIndex].split('=')
                    if len(stringList) == 2:
                        return stringList[1]

        return "unknoen"

    #退出按钮
    def quitBtn_clicked(self):

        self.close()

    #关闭事件
    def closeEvent(self, QCloseEvent):
        self.sendMessage(MessageType.ParticipantLeft)
        QCloseEvent.accept()




        """
            #获取IP地址
    def getIP(self):
        list1 = QNetworkInterface.allAddresses();
        for address in list1:
            if address.protocol()==QAbstractSocket.IPv4Protocol :
                print("ip "+address.toString())
                return address.toString()

        return 0

"""



        

if __name__ == '__main__':
    app = QApplication(sys.argv)
    QTextCodec.setCodecForLocale(QTextCodec.codecForLocale())
    win = UdpChatRoom()
    win.show()
    sys.exit(app.exec_())



